library(tidyverse)
Warning: package ‘tidyverse’ was built under R version 4.0.5
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ----------------------------------------------------------------------- tidyverse 1.3.1 --
v ggplot2 3.3.3     v purrr   0.3.4
v tibble  3.1.0     v dplyr   1.0.5
v tidyr   1.1.3     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.1
Warning: package ‘ggplot2’ was built under R version 4.0.4
Warning: package ‘tibble’ was built under R version 4.0.5
Warning: package ‘tidyr’ was built under R version 4.0.4
Warning: package ‘dplyr’ was built under R version 4.0.4
Warning: package ‘forcats’ was built under R version 4.0.4
-- Conflicts -------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(janitor)    # for data cleaning
Warning: package ‘janitor’ was built under R version 4.0.4

Attaching package: ‘janitor’

The following objects are masked from ‘package:stats’:

    chisq.test, fisher.test
library(readxl)     # for readig excel files
library(visdat)     # for a quick look at data quality
Warning: package ‘visdat’ was built under R version 4.0.4

Processing the data

Gardens data

Dataset downloaded from ONS on 5th June 2021. Both gardens space and public parks datasets are the April 2020 versions.

# get a quick visual summary of data types and the amount of missing data
gardens %>% 
  visdat::vis_dat()


gardens %>% 
  visdat::vis_miss()

Indicies of multiple deprivation

ONS released the 2019 IMD data at LSOA scale. MySociety have produced IMD at various other scales including the MSOA scale.

imd_2019 <- read_csv("data/imd2019_msoa_level_data.csv")

-- Column specification ----------------------------------------------------------------------------------------
cols(
  MSOAC = col_character(),
  MSOAHOCLN = col_character(),
  LAD19C = col_character(),
  LAD19N = col_character(),
  REG = col_character(),
  LSOACOUNT = col_double(),
  POPMID15 = col_double(),
  `IMD19 SCORE` = col_double(),
  MSOARANK = col_double(),
  MSOADECILE = col_double(),
  MSOAQUINTILE = col_double()
)
imd_2019

Population data

ONS provide MSOA level population data. Here I use the most recent release (mid 2019).

msoa_pops <- read_xlsx(
  
  "data/SAPE22DT4-mid-2019-msoa-syoa-estimates-unformatted.xlsx",
  sheet = "Mid-2019 Persons",
  skip = 4) %>% 
  
  # process variable names for conistency
  janitor::clean_names() %>% 
  
  # select minimal number of columns
  select(msoa_code, population = all_ages)

msoa_pops %>% 
  visdat::vis_miss()

Transforming the data for plotting

Overall average = 2.4 (2020 see here)

2017-18 was the most year I could find on average occupancy figures broken down by house/flat from MCHLG:

  • House = 2.5 people

  • High-rise flat = 1.9

  • Mid-rise flat = 1.8

More details here.

So for now, I’ll make a conservative assumption that the average occupancy for a flat is 1.8 (i.e. the lower of the mid and high rise figures above).

I looked at trying to estimate more accurately, but the figures for the number of dwellings per block are not available.

2020 estimates of the numbers of high and mid rise flat can be found here. These can be used to calculate an average flat occupancy rate.

  • 12,500 blocks of high rise flats

  • 77,500 blocks of mid rise flats

# calculate scaling factors for ave occupancy in an MSOA
# from national data
nat_ave_occ <- 2.4
nat_house_ave_occ <- 2.5
nat_flat_ave_occ <- 1.9

flat_scale <- nat_flat_ave_occ / nat_ave_occ
house_scale <- nat_house_ave_occ / nat_ave_occ


people_wo_gar <- gardens %>% 
  left_join(msoa_pops) %>% 
  mutate(house_ad_without_gar_count = houses_ad_count - houses_ad_with_gar_count,
         flats_ad_without_gar_count = flats_ad_count - flats_ad_with_gar_count,
         ave_occ = population / ad_count,
         ave_occ_flat = flat_scale * ave_occ,
         ave_occ_house = house_scale * ave_occ,
         pop_calc = (ave_occ_flat * flats_ad_count) + (ave_occ_house * houses_ad_count),
         pop_diff = population - pop_calc) 
Joining, by = "msoa_code"
ggplot(people_wo_gar, aes(pop_diff)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1282 rows containing non-finite values (stat_bin).

NA

May be more accurate to just use average occupancy rates for each MSOA??

people_wo_gar <- gardens %>% 
  left_join(msoa_pops) %>% 
  mutate(ad_wo_gar = ad_count * (1 - perc_of_ades_with_gar),
         ave_occ = population / ad_count,
         people_wo_gar = round(ad_wo_gar * ave_occ)) %>% 
  select(country_code:msoa_name, people_wo_gar)
Joining, by = "msoa_code"
people_wo_gar

ggplot(people_wo_gar, aes(people_wo_gar)) +
  geom_histogram()
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Warning: Removed 1282 rows containing non-finite values (stat_bin).

https://www.robert-hickman.eu/post/getis-ord-heatmaps-tutorial/

library(sf)

# focus on Englnad and Wales
# (as shapefile for MSOAs only inlcudes England and Wales)
people_wo_gar_EW <- people_wo_gar %>% 
  filter(country_name == "England" |
         country_name == "Wales")

median_msoa_peop_wo_gar = median(people_wo_gar_EW$people_wo_gar, na.rm = TRUE)


# read in MSOA boundary shapefile
msoa_bound <- st_read("data/MSOA_bound/Middle_Layer_Super_Output_Areas_(December_2011)_Boundaries.shp") %>% 
  select(msoa_code = msoa11cd, 
         msoa_name = msoa11nm)
Reading layer `Middle_Layer_Super_Output_Areas_(December_2011)_Boundaries' from data source `C:\Users\chris\Desktop\Data Analysis Projects\green_space\data\MSOA_bound\Middle_Layer_Super_Output_Areas_(December_2011)_Boundaries.shp' using driver `ESRI Shapefile'
Simple feature collection with 7201 features and 6 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 82678 ymin: 5343 xmax: 655604.7 ymax: 657534.1
Projected CRS: OSGB 1936 / British National Grid
# read in countries boundary shapefile (for clipping polygon grid)
country_bound <- st_read("data/Countries_bound/Countries_(December_2017)_Boundaries.shp") %>% 
  filter(ctry17nm == "England" | ctry17nm == "Wales")
Reading layer `Countries_(December_2017)_Boundaries' from data source `C:\Users\chris\Desktop\Data Analysis Projects\green_space\data\Countries_bound\Countries_(December_2017)_Boundaries.shp' using driver `ESRI Shapefile'
Simple feature collection with 3 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5512.999 ymin: 5351.297 xmax: 655644.8 ymax: 1220302
Projected CRS: OSGB 1936 / British National Grid
# join garden data with
people_wo_gar_spatial <- msoa_bound %>% 
  left_join(people_wo_gar_EW) %>% 
  
  # median imputation for one msoa with missing
  mutate(people_wo_gar = replace_na(people_wo_gar, median_msoa_peop_wo_gar))
Joining, by = c("msoa_code", "msoa_name")
  


# ###########################
# simulate the locations of people without a garden
# ###########################

# random locations withi an MSOA was too computationally intesnive
# so I went with placing the 'people' at MSOA centroids
people <- people_wo_gar_spatial %>% 
  mutate(people_wo_gar = round(people_wo_gar / 10),
         geometry = st_centroid(geometry)) %>% 
  uncount(people_wo_gar)


sum(people_wo_gar_spatial$people_wo_gar)
[1] 6702350
# create boundary file
map_bound <- people_wo_gar_spatial %>%
  summarise()# %>% 
  #st_transform(4326)

# people <- st_sample(
#   select(people_wo_gar_spatial, -people_wo_gar),
#   size = round(people_wo_gar_spatial$people_wo_gar / 100))

# ###########################
# create hexagonal grid
# ###########################

hex_polygons <- st_make_grid(map_bound, 7500,
                             crs = st_crs(people_wo_gar_spatial),
                             what = "polygons",
                             square = FALSE) %>% 
  st_sf()

# calculate number of people in each polygon
intersects <- st_intersects(hex_polygons, people)
hex_polygons$people_wo_gar <- lengths(intersects)

# ###########################
# create the plot
# ###########################
# ggplot(people_wo_gar_spatial) +
#   #geom_sf(data = map_bound, colour = "black", size = 1) +
#   geom_sf(data = hex_polygons, fill = "black") + # , aes(fill = people_wo_gar)
#   scale_fill_viridis_c(trans = "log", direction = -1) +
#   #scale_color_viridis_c(trans = "log") +
#   ggthemes::theme_map()

# crop hexogens to outline of England and Wales
hex_polygons_EW <- hex_polygons[country_bound, ]

# hex_polygon_EW %>% 
#   count(people_wo_gar)

ggplot() +
  #geom_sf(data = map_bound) +
  #geom_sf(data = st_centroid(msoa_bound), colour = "grey") +
  geom_sf(data = hex_polygons_EW, alpha = 0.5, mapping = aes(fill = people_wo_gar)) +
  scale_fill_viridis_c(trans = "log", direction = -1) +
  theme_void()
Warning: Transformation introduced infinite values in discrete y-axis

  
# hex_polygons %>% 
#   filter(people_wo_gar == 0)
# 
# people_wo_gar_spatial %>% 
#   filter(people_wo_gar == 0)

# ###########################
# Smooth
# ###########################

https://pudding.cool/process/regional_smoothing/

Looking at change in park usage (in two periods in 2020) vs garden access.

Usage data from Google via ONS

ggplot(gar_park_use, aes(prop_ad_wo_gar, perc_ch_parks_spring_lock,
                         colour = is_urban_LAD)) +
  geom_point() +
  geom_smooth(method = "lm") +
  #scale_x_log10() +
  xlim(c(0,0.5)) +
  facet_wrap(~is_urban_LAD)
`geom_smooth()` using formula 'y ~ x'
Warning: Removed 5 rows containing non-finite values (stat_smooth).
Warning: Removed 5 rows containing missing values (geom_point).

p4 <- ggplot(filter(gar_park_use_foe_eng, prop_urban > 0.8), 
       aes(perc_ch_parks_spring_lock, perc_ch_park_summer,
           colour = prop_ad_wo_gar,
           size = green_space_area_per_capita,
           label = lad_name)) +
  geom_point(alpha = 0.5)+
  scale_colour_viridis_c(direction = -1, trans = "log", end = 0.9)

p4
Warning: Removed 7 rows containing missing values (geom_point).

plotly::ggplotly(p4)

Major cities

p
Warning: Using size for a discrete variable is not advised.
Warning: Removed 1 rows containing missing values (geom_point).

LA_bounds
Simple feature collection with 382 features and 10 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -116.1928 ymin: 5337.901 xmax: 655653.8 ymax: 1220302
Projected CRS: OSGB 1936 / British National Grid
First 10 features:
   objectid   lad19cd                     lad19nm lad19nmw  bng_e  bng_n     long      lat st_areasha
1         1 E06000001                  Hartlepool     <NA> 447160 531474 -1.27018 54.67614   93712620
2         2 E06000002               Middlesbrough     <NA> 451141 516887 -1.21099 54.54467   53881564
3         3 E06000003        Redcar and Cleveland     <NA> 464361 519597 -1.00608 54.56752  245069509
4         4 E06000004            Stockton-on-Tees     <NA> 444940 518183 -1.30664 54.55691  204932954
5         5 E06000005                  Darlington     <NA> 428029 515648 -1.56835 54.53534  197475689
6         6 E06000006                      Halton     <NA> 354246 382146 -2.68853 53.33424   79084035
7         7 E06000007                  Warrington     <NA> 362744 388456 -2.56167 53.39163  180627984
8         8 E06000008       Blackburn with Darwen     <NA> 369490 422806 -2.46360 53.70080  137022080
9         9 E06000009                   Blackpool     <NA> 332819 436635 -3.02199 53.82164   34870886
10       10 E06000010 Kingston upon Hull, City of     <NA> 511894 431650 -0.30382 53.76920   71583612
   st_lengths                       geometry
1    71011.93 MULTIPOLYGON (((447213.9 53...
2    44481.69 MULTIPOLYGON (((448609.9 52...
3    96703.99 MULTIPOLYGON (((455932.3 52...
4   123408.99 MULTIPOLYGON (((444157 5279...
5   107206.40 MULTIPOLYGON (((423496.6 52...
6    77771.10 MULTIPOLYGON (((358374.7 38...
7   114690.86 MULTIPOLYGON (((367308.2 39...
8    65284.97 MULTIPOLYGON (((369226.3 43...
9    34483.49 MULTIPOLYGON (((332985.7 44...
10   64681.12 MULTIPOLYGON (((510966.6 43...
LS0tDQp0aXRsZTogIkVzdGltYXRpbmcgdGhlIG51bWJlciBvZiBwZW9wbGUgd2l0aG91dCBhIGdhcmRlbiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQoNCmxpYnJhcnkoamFuaXRvcikgICAgIyBmb3IgZGF0YSBjbGVhbmluZw0KbGlicmFyeShyZWFkeGwpICAgICAjIGZvciByZWFkaWcgZXhjZWwgZmlsZXMNCmxpYnJhcnkodmlzZGF0KSAgICAgIyBmb3IgYSBxdWljayBsb29rIGF0IGRhdGEgcXVhbGl0eQ0KYGBgDQoNCmBgYHtyfQ0KdGhlbWVfc2V0KHRoZW1lX2xpZ2h0KCkpDQpgYGANCg0KIyMgUHJvY2Vzc2luZyB0aGUgZGF0YQ0KDQojIyMgR2FyZGVucyBkYXRhDQoNCkRhdGFzZXQgZG93bmxvYWRlZCBmcm9tIFtPTlNdKGh0dHBzOi8vd3d3Lm9ucy5nb3YudWsvZWNvbm9teS9lbnZpcm9ubWVudGFsYWNjb3VudHMvZGF0YXNldHMvYWNjZXNzdG9nYXJkZW5zYW5kcHVibGljZ3JlZW5zcGFjZWluZ3JlYXRicml0YWluKSBvbiA1dGggSnVuZSAyMDIxLiBCb3RoIGdhcmRlbnMgc3BhY2UgYW5kIHB1YmxpYyBwYXJrcyBkYXRhc2V0cyBhcmUgdGhlIEFwcmlsIDIwMjAgdmVyc2lvbnMuDQoNCmBgYHtyfQ0KIyBhIGNvbnZlbmllbmNlIGZ1bmN0aW9uIGZvciByZW5hbWluZyBjb2x1bW5zDQojIEkgYW0gc3VyZSB0aGVyZSBpcyBhIGJldHRlciB3YXkgdG8gZG8gdGhpcyENCnJlcGxhY2VfaW5fY29sdW1uX25hbWUgPC0gZnVuY3Rpb24oZGYsIHBhdHRlcm4sIHJlcGxhY2VtZW50KXsNCiAgZGYgJT4lIA0KICAgIHJlbmFtZV93aXRoKC5mbiA9IH4gc3RyX3JlcGxhY2UoLngsIHBhdHRlcm4sIHJlcGxhY2VtZW50KSkNCn0NCg0KIyByZWFkIGluIGFuZCBjbGVhbiBkYXRhDQpnYXJkZW5zIDwtIHJlYWRfeGxzeCgNCiAgImRhdGEvb3Nwcml2YXRlb3V0ZG9vcnNwYWNlcmVmZXJlbmNldGFibGVzX2VkaXRlZF9mb3JfaW1wb3J0Lnhsc3giLA0KICBzaGVldCA9ICJNU09BIGdhcmRlbnMiLCANCiAgc2tpcCA9IDEpICU+JSANCiAgDQogICMgbWFrZSB2YXJpYWJsZXMgbmFtZXMgbW9yZSBjb25pc3RlbnQNCiAgamFuaXRvcjo6Y2xlYW5fbmFtZXMoKSAlPiUgDQogIA0KICAjIGZvY3VzIG9uIHZhcmlhYmxlcyBvZiBpbnRlcmVzdCANCiAgc2VsZWN0KGNvdW50cnlfY29kZTptc29hX25hbWUsDQogICAgICAgICBlbmRzX3dpdGgoImNvdW50IikgfA0KICAgICAgICAgc3RhcnRzX3dpdGgoInRvdGFsIikpICU+JSANCiAgDQogICMgc2ltcGxpZnkgdmFyaWFibGVzIG5hbWVzIChub3cgZGF0YSBieSBob3VzaW5nIHR5cGUgaGFzIGJlZW4gcmVtb3ZlZCkNCiAgcmVwbGFjZV9pbl9jb2x1bW5fbmFtZSgidG90YWxfIiwgIiIpICU+JSANCiAgcmVwbGFjZV9pbl9jb2x1bW5fbmFtZSgicHJpdmF0ZV9vdXRkb29yX3NwYWNlIiwgImdhciIpICU+JSANCiAgcmVwbGFjZV9pbl9jb2x1bW5fbmFtZSgiYWRkcmVzcyIsICJhZCIpICU+JSANCiAgcmVwbGFjZV9pbl9jb2x1bW5fbmFtZSgiYWRyZXNzIiwgImFkIikgJT4lDQogIHJlcGxhY2VfaW5fY29sdW1uX25hbWUoImFkcmVzc2VzIiwgImFkcyIpICU+JSANCiAgcmVwbGFjZV9pbl9jb2x1bW5fbmFtZSgicGVyY2VudGFnZSIsICJwZXJjIikgJT4lIA0KICByZXBsYWNlX2luX2NvbHVtbl9uYW1lKCJfbTIiLCAiIikgJT4lIA0KICByZXBsYWNlX2luX2NvbHVtbl9uYW1lKCJhdmVyYWdlIiwgImF2ZSIpDQoNCiMgZGlzcGxheSBkYXRhIGZvciBxdWljayB2aXN1YWwgY2hlY2tzDQpnYXJkZW5zDQogIA0KICANCmBgYA0KDQpgYGB7cn0NCiMgZ2V0IGEgcXVpY2sgdmlzdWFsIHN1bW1hcnkgb2YgZGF0YSB0eXBlcyBhbmQgdGhlIGFtb3VudCBvZiBtaXNzaW5nIGRhdGENCmdhcmRlbnMgJT4lIA0KICB2aXNkYXQ6OnZpc19kYXQoKQ0KDQpnYXJkZW5zICU+JSANCiAgdmlzZGF0Ojp2aXNfbWlzcygpDQpgYGANCg0KIyMjIEluZGljaWVzIG9mIG11bHRpcGxlIGRlcHJpdmF0aW9uDQoNCk9OUyByZWxlYXNlZCB0aGUgMjAxOSBJTUQgZGF0YSBhdCBMU09BIHNjYWxlLiBNeVNvY2lldHkgaGF2ZSBwcm9kdWNlZCBbSU1EIGF0IHZhcmlvdXMgb3RoZXIgc2NhbGVzXShodHRwczovL3Jlc2VhcmNoLm15c29jaWV0eS5vcmcvc2l0ZXMvaW1kMjAxOS9hYm91dC8pIGluY2x1ZGluZyB0aGUgTVNPQSBzY2FsZS4NCg0KYGBge3J9DQppbWRfMjAxOSA8LSByZWFkX2NzdigiZGF0YS9pbWQyMDE5X21zb2FfbGV2ZWxfZGF0YS5jc3YiKQ0KaW1kXzIwMTkNCmBgYA0KDQojIyMgUG9wdWxhdGlvbiBkYXRhDQoNCk9OUyBwcm92aWRlIFtNU09BIGxldmVsIHBvcHVsYXRpb24gZGF0YV0oaHR0cHM6Ly93d3cub25zLmdvdi51ay9wZW9wbGVwb3B1bGF0aW9uYW5kY29tbXVuaXR5L3BvcHVsYXRpb25hbmRtaWdyYXRpb24vcG9wdWxhdGlvbmVzdGltYXRlcy9kYXRhc2V0cy9taWRkbGVzdXBlcm91dHB1dGFyZWFtaWR5ZWFycG9wdWxhdGlvbmVzdGltYXRlcykuIEhlcmUgSSB1c2UgdGhlIG1vc3QgcmVjZW50IHJlbGVhc2UgKG1pZCAyMDE5KS4NCg0KYGBge3J9DQptc29hX3BvcHMgPC0gcmVhZF94bHN4KA0KICANCiAgImRhdGEvU0FQRTIyRFQ0LW1pZC0yMDE5LW1zb2Etc3lvYS1lc3RpbWF0ZXMtdW5mb3JtYXR0ZWQueGxzeCIsDQogIHNoZWV0ID0gIk1pZC0yMDE5IFBlcnNvbnMiLA0KICBza2lwID0gNCkgJT4lIA0KICANCiAgIyBwcm9jZXNzIHZhcmlhYmxlIG5hbWVzIGZvciBjb25pc3RlbmN5DQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkgJT4lIA0KICANCiAgIyBzZWxlY3QgbWluaW1hbCBudW1iZXIgb2YgY29sdW1ucw0KICBzZWxlY3QobXNvYV9jb2RlLCBwb3B1bGF0aW9uID0gYWxsX2FnZXMpDQoNCm1zb2FfcG9wcyAlPiUgDQogIHZpc2RhdDo6dmlzX21pc3MoKQ0KYGBgDQoNCiMjIyBUcmFuc2Zvcm1pbmcgdGhlIGRhdGEgZm9yIHBsb3R0aW5nDQoNCk92ZXJhbGwgYXZlcmFnZSA9IDIuNCAoMjAyMCBzZWUgW2hlcmVdKGh0dHBzOi8vd3d3Lm9ucy5nb3YudWsvcGVvcGxlcG9wdWxhdGlvbmFuZGNvbW11bml0eS9iaXJ0aHNkZWF0aHNhbmRtYXJyaWFnZXMvZmFtaWxpZXMvYnVsbGV0aW5zL2ZhbWlsaWVzYW5kaG91c2Vob2xkcy8yMDIwKSkNCg0KMjAxNy0xOCB3YXMgdGhlIG1vc3QgeWVhciBJIGNvdWxkIGZpbmQgb24gW2F2ZXJhZ2Ugb2NjdXBhbmN5IGZpZ3VyZXMgYnJva2VuIGRvd24gYnkgaG91c2UvZmxhdCBmcm9tIE1DSExHXShodHRwczovL2Fzc2V0cy5wdWJsaXNoaW5nLnNlcnZpY2UuZ292LnVrL2dvdmVybm1lbnQvdXBsb2Fkcy9zeXN0ZW0vdXBsb2Fkcy9hdHRhY2htZW50X2RhdGEvZmlsZS84MTcyODYvRUhTXzIwMTctMThfSG91c2Vob2xkc19SZXBvcnQucGRmKToNCg0KLSAgIEhvdXNlID0gMi41IHBlb3BsZQ0KDQotICAgSGlnaC1yaXNlIGZsYXQgPSAxLjkNCg0KLSAgIE1pZC1yaXNlIGZsYXQgPSAxLjgNCg0KTW9yZSBkZXRhaWxzIFtoZXJlXShodHRwczovL3d3dy5nb3YudWsvZ292ZXJubWVudC9zdGF0aXN0aWNzL2VuZ2xpc2gtaG91c2luZy1zdXJ2ZXktMjAxNy10by0yMDE4LWhvdXNlaG9sZHMpLg0KDQpTbyBmb3Igbm93LCBJJ2xsIG1ha2UgYSBjb25zZXJ2YXRpdmUgYXNzdW1wdGlvbiB0aGF0IHRoZSBhdmVyYWdlIG9jY3VwYW5jeSBmb3IgYSBmbGF0IGlzIDEuOCAoaS5lLiB0aGUgbG93ZXIgb2YgdGhlIG1pZCBhbmQgaGlnaCByaXNlIGZpZ3VyZXMgYWJvdmUpLg0KDQoqKkkgbG9va2VkIGF0IHRyeWluZyB0byBlc3RpbWF0ZSBtb3JlIGFjY3VyYXRlbHksIGJ1dCB0aGUgZmlndXJlcyBmb3IgdGhlIG51bWJlciBvZiBkd2VsbGluZ3MgcGVyIGJsb2NrIGFyZSBub3QgYXZhaWxhYmxlLioqDQoNCjIwMjAgZXN0aW1hdGVzIG9mIHRoZSBudW1iZXJzIG9mIGhpZ2ggYW5kIG1pZCByaXNlIGZsYXQgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3d3dy5nb3YudWsvZ292ZXJubWVudC9wdWJsaWNhdGlvbnMvYnVpbGRpbmctc2FmZXR5LXByb2dyYW1tZS1lc3RpbWF0ZXMtb2YtZXdzMS1yZXF1aXJlbWVudHMtb24tcmVzaWRlbnRpYWwtYnVpbGRpbmdzLWluLWVuZ2xhbmQvYnVpbGRpbmctc2FmZXR5LXByb2dyYW1tZS1lc3RpbWF0ZXMtb2YtZXdzMS1yZXF1aXJlbWVudHMtb24tcmVzaWRlbnRpYWwtYnVpbGRpbmdzLWluLWVuZ2xhbmQpLiBUaGVzZSBjYW4gYmUgdXNlZCB0byBjYWxjdWxhdGUgYW4gYXZlcmFnZSBmbGF0IG9jY3VwYW5jeSByYXRlLg0KDQotICAgMTIsNTAwIGJsb2NrcyBvZiBoaWdoIHJpc2UgZmxhdHMNCg0KLSAgIDc3LDUwMCBibG9ja3Mgb2YgbWlkIHJpc2UgZmxhdHMNCg0KYGBge3J9DQojIGNhbGN1bGF0ZSBzY2FsaW5nIGZhY3RvcnMgZm9yIGF2ZSBvY2N1cGFuY3kgaW4gYW4gTVNPQQ0KIyBmcm9tIG5hdGlvbmFsIGRhdGENCm5hdF9hdmVfb2NjIDwtIDIuNA0KbmF0X2hvdXNlX2F2ZV9vY2MgPC0gMi41DQpuYXRfZmxhdF9hdmVfb2NjIDwtIDEuOQ0KDQpmbGF0X3NjYWxlIDwtIG5hdF9mbGF0X2F2ZV9vY2MgLyBuYXRfYXZlX29jYw0KaG91c2Vfc2NhbGUgPC0gbmF0X2hvdXNlX2F2ZV9vY2MgLyBuYXRfYXZlX29jYw0KDQoNCnBlb3BsZV93b19nYXIgPC0gZ2FyZGVucyAlPiUgDQogIGxlZnRfam9pbihtc29hX3BvcHMpICU+JSANCiAgbXV0YXRlKGhvdXNlX2FkX3dpdGhvdXRfZ2FyX2NvdW50ID0gaG91c2VzX2FkX2NvdW50IC0gaG91c2VzX2FkX3dpdGhfZ2FyX2NvdW50LA0KICAgICAgICAgZmxhdHNfYWRfd2l0aG91dF9nYXJfY291bnQgPSBmbGF0c19hZF9jb3VudCAtIGZsYXRzX2FkX3dpdGhfZ2FyX2NvdW50LA0KICAgICAgICAgYXZlX29jYyA9IHBvcHVsYXRpb24gLyBhZF9jb3VudCwNCiAgICAgICAgIGF2ZV9vY2NfZmxhdCA9IGZsYXRfc2NhbGUgKiBhdmVfb2NjLA0KICAgICAgICAgYXZlX29jY19ob3VzZSA9IGhvdXNlX3NjYWxlICogYXZlX29jYywNCiAgICAgICAgIHBvcF9jYWxjID0gKGF2ZV9vY2NfZmxhdCAqIGZsYXRzX2FkX2NvdW50KSArIChhdmVfb2NjX2hvdXNlICogaG91c2VzX2FkX2NvdW50KSwNCiAgICAgICAgIHBvcF9kaWZmID0gcG9wdWxhdGlvbiAtIHBvcF9jYWxjKSANCg0KZ2dwbG90KHBlb3BsZV93b19nYXIsIGFlcyhwb3BfZGlmZikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KICANCmBgYA0KDQpNYXkgYmUgbW9yZSBhY2N1cmF0ZSB0byBqdXN0IHVzZSBhdmVyYWdlIG9jY3VwYW5jeSByYXRlcyBmb3IgZWFjaCBNU09BPz8NCg0KYGBge3J9DQpwZW9wbGVfd29fZ2FyIDwtIGdhcmRlbnMgJT4lIA0KICBsZWZ0X2pvaW4obXNvYV9wb3BzKSAlPiUgDQogIG11dGF0ZShhZF93b19nYXIgPSBhZF9jb3VudCAqICgxIC0gcGVyY19vZl9hZGVzX3dpdGhfZ2FyKSwNCiAgICAgICAgIGF2ZV9vY2MgPSBwb3B1bGF0aW9uIC8gYWRfY291bnQsDQogICAgICAgICBwZW9wbGVfd29fZ2FyID0gcm91bmQoYWRfd29fZ2FyICogYXZlX29jYykpICU+JSANCiAgc2VsZWN0KGNvdW50cnlfY29kZTptc29hX25hbWUsIHBlb3BsZV93b19nYXIpDQoNCnBlb3BsZV93b19nYXINCg0KZ2dwbG90KHBlb3BsZV93b19nYXIsIGFlcyhwZW9wbGVfd29fZ2FyKSkgKw0KICBnZW9tX2hpc3RvZ3JhbSgpDQoNCmBgYA0KDQo8aHR0cHM6Ly93d3cucm9iZXJ0LWhpY2ttYW4uZXUvcG9zdC9nZXRpcy1vcmQtaGVhdG1hcHMtdHV0b3JpYWwvPg0KDQpgYGB7cn0NCmxpYnJhcnkoc2YpDQoNCiMgZm9jdXMgb24gRW5nbG5hZCBhbmQgV2FsZXMNCiMgKGFzIHNoYXBlZmlsZSBmb3IgTVNPQXMgb25seSBpbmxjdWRlcyBFbmdsYW5kIGFuZCBXYWxlcykNCnBlb3BsZV93b19nYXJfRVcgPC0gcGVvcGxlX3dvX2dhciAlPiUgDQogIGZpbHRlcihjb3VudHJ5X25hbWUgPT0gIkVuZ2xhbmQiIHwNCiAgICAgICAgIGNvdW50cnlfbmFtZSA9PSAiV2FsZXMiKQ0KDQptZWRpYW5fbXNvYV9wZW9wX3dvX2dhciA9IG1lZGlhbihwZW9wbGVfd29fZ2FyX0VXJHBlb3BsZV93b19nYXIsIG5hLnJtID0gVFJVRSkNCg0KDQojIHJlYWQgaW4gTVNPQSBib3VuZGFyeSBzaGFwZWZpbGUNCm1zb2FfYm91bmQgPC0gc3RfcmVhZCgiZGF0YS9NU09BX2JvdW5kL01pZGRsZV9MYXllcl9TdXBlcl9PdXRwdXRfQXJlYXNfKERlY2VtYmVyXzIwMTEpX0JvdW5kYXJpZXMuc2hwIikgJT4lIA0KICBzZWxlY3QobXNvYV9jb2RlID0gbXNvYTExY2QsIA0KICAgICAgICAgbXNvYV9uYW1lID0gbXNvYTExbm0pDQoNCiMgcmVhZCBpbiBjb3VudHJpZXMgYm91bmRhcnkgc2hhcGVmaWxlIChmb3IgY2xpcHBpbmcgcG9seWdvbiBncmlkKQ0KY291bnRyeV9ib3VuZCA8LSBzdF9yZWFkKCJkYXRhL0NvdW50cmllc19ib3VuZC9Db3VudHJpZXNfKERlY2VtYmVyXzIwMTcpX0JvdW5kYXJpZXMuc2hwIikgJT4lIA0KICBmaWx0ZXIoY3RyeTE3bm0gPT0gIkVuZ2xhbmQiIHwgY3RyeTE3bm0gPT0gIldhbGVzIikNCg0KIyBqb2luIGdhcmRlbiBkYXRhIHdpdGgNCnBlb3BsZV93b19nYXJfc3BhdGlhbCA8LSBtc29hX2JvdW5kICU+JSANCiAgbGVmdF9qb2luKHBlb3BsZV93b19nYXJfRVcpICU+JSANCiAgDQogICMgbWVkaWFuIGltcHV0YXRpb24gZm9yIG9uZSBtc29hIHdpdGggbWlzc2luZw0KICBtdXRhdGUocGVvcGxlX3dvX2dhciA9IHJlcGxhY2VfbmEocGVvcGxlX3dvX2dhciwgbWVkaWFuX21zb2FfcGVvcF93b19nYXIpKQ0KICANCg0KDQojICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBzaW11bGF0ZSB0aGUgbG9jYXRpb25zIG9mIHBlb3BsZSB3aXRob3V0IGEgZ2FyZGVuDQojICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIHJhbmRvbSBsb2NhdGlvbnMgd2l0aGkgYW4gTVNPQSB3YXMgdG9vIGNvbXB1dGF0aW9uYWxseSBpbnRlc25pdmUNCiMgc28gSSB3ZW50IHdpdGggcGxhY2luZyB0aGUgJ3Blb3BsZScgYXQgTVNPQSBjZW50cm9pZHMNCnBlb3BsZSA8LSBwZW9wbGVfd29fZ2FyX3NwYXRpYWwgJT4lIA0KICBtdXRhdGUocGVvcGxlX3dvX2dhciA9IHJvdW5kKHBlb3BsZV93b19nYXIgLyAxMCksDQogICAgICAgICBnZW9tZXRyeSA9IHN0X2NlbnRyb2lkKGdlb21ldHJ5KSkgJT4lIA0KICB1bmNvdW50KHBlb3BsZV93b19nYXIpDQoNCg0Kc3VtKHBlb3BsZV93b19nYXJfc3BhdGlhbCRwZW9wbGVfd29fZ2FyKQ0KIyBjcmVhdGUgYm91bmRhcnkgZmlsZQ0KbWFwX2JvdW5kIDwtIHBlb3BsZV93b19nYXJfc3BhdGlhbCAlPiUNCiAgc3VtbWFyaXNlKCkjICU+JSANCiAgI3N0X3RyYW5zZm9ybSg0MzI2KQ0KDQojIHBlb3BsZSA8LSBzdF9zYW1wbGUoDQojICAgc2VsZWN0KHBlb3BsZV93b19nYXJfc3BhdGlhbCwgLXBlb3BsZV93b19nYXIpLA0KIyAgIHNpemUgPSByb3VuZChwZW9wbGVfd29fZ2FyX3NwYXRpYWwkcGVvcGxlX3dvX2dhciAvIDEwMCkpDQoNCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIGNyZWF0ZSBoZXhhZ29uYWwgZ3JpZA0KIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KaGV4X3BvbHlnb25zIDwtIHN0X21ha2VfZ3JpZChtYXBfYm91bmQsIDc1MDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNycyA9IHN0X2NycyhwZW9wbGVfd29fZ2FyX3NwYXRpYWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3aGF0ID0gInBvbHlnb25zIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3F1YXJlID0gRkFMU0UpICU+JSANCiAgc3Rfc2YoKQ0KDQojIGNhbGN1bGF0ZSBudW1iZXIgb2YgcGVvcGxlIGluIGVhY2ggcG9seWdvbg0KaW50ZXJzZWN0cyA8LSBzdF9pbnRlcnNlY3RzKGhleF9wb2x5Z29ucywgcGVvcGxlKQ0KaGV4X3BvbHlnb25zJHBlb3BsZV93b19nYXIgPC0gbGVuZ3RocyhpbnRlcnNlY3RzKQ0KDQojICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBjcmVhdGUgdGhlIHBsb3QNCiMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIGdncGxvdChwZW9wbGVfd29fZ2FyX3NwYXRpYWwpICsNCiMgICAjZ2VvbV9zZihkYXRhID0gbWFwX2JvdW5kLCBjb2xvdXIgPSAiYmxhY2siLCBzaXplID0gMSkgKw0KIyAgIGdlb21fc2YoZGF0YSA9IGhleF9wb2x5Z29ucywgZmlsbCA9ICJibGFjayIpICsgIyAsIGFlcyhmaWxsID0gcGVvcGxlX3dvX2dhcikNCiMgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyh0cmFucyA9ICJsb2ciLCBkaXJlY3Rpb24gPSAtMSkgKw0KIyAgICNzY2FsZV9jb2xvcl92aXJpZGlzX2ModHJhbnMgPSAibG9nIikgKw0KIyAgIGdndGhlbWVzOjp0aGVtZV9tYXAoKQ0KDQojIGNyb3AgaGV4b2dlbnMgdG8gb3V0bGluZSBvZiBFbmdsYW5kIGFuZCBXYWxlcw0KaGV4X3BvbHlnb25zX0VXIDwtIGhleF9wb2x5Z29uc1tjb3VudHJ5X2JvdW5kLCBdDQoNCiMgaGV4X3BvbHlnb25fRVcgJT4lIA0KIyAgIGNvdW50KHBlb3BsZV93b19nYXIpDQoNCmdncGxvdCgpICsNCiAgI2dlb21fc2YoZGF0YSA9IG1hcF9ib3VuZCkgKw0KICAjZ2VvbV9zZihkYXRhID0gc3RfY2VudHJvaWQobXNvYV9ib3VuZCksIGNvbG91ciA9ICJncmV5IikgKw0KICBnZW9tX3NmKGRhdGEgPSBoZXhfcG9seWdvbnNfRVcsIGFscGhhID0gMC41LCBtYXBwaW5nID0gYWVzKGZpbGwgPSBwZW9wbGVfd29fZ2FyKSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYyh0cmFucyA9ICJsb2ciLCBkaXJlY3Rpb24gPSAtMSkgKw0KICB0aGVtZV92b2lkKCkNCiAgDQojIGhleF9wb2x5Z29ucyAlPiUgDQojICAgZmlsdGVyKHBlb3BsZV93b19nYXIgPT0gMCkNCiMgDQojIHBlb3BsZV93b19nYXJfc3BhdGlhbCAlPiUgDQojICAgZmlsdGVyKHBlb3BsZV93b19nYXIgPT0gMCkNCg0KIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgU21vb3RoDQojICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQoNCg0KYGBgDQoNCjxodHRwczovL3B1ZGRpbmcuY29vbC9wcm9jZXNzL3JlZ2lvbmFsX3Ntb290aGluZy8+DQoNCmBgYHtyfQ0KbGlicmFyeShzcGRlcCkNCg0KIyBjb252ZXJ0IGdlby1kZiB0byBwbGFpbiBkZg0KaGV4X3BvbHlnb25zX0VXX2RmIDwtIGhleF9wb2x5Z29uc19FVyAlPiUgDQogIHN0X2Ryb3BfZ2VvbWV0cnkoKQ0KDQojIGdldCBjZW50cm9pZCBvZiBlYWNoIGhleGFnb24NCmhleF9jZW50cm9pZHMgPC0gaGV4X3BvbHlnb25zX0VXICU+JSANCiAgbXV0YXRlKGdlb21ldHJ5ID0gc3RfY2VudHJvaWQoZ2VvbWV0cnkpKQ0KDQojIGZpbmQgayBuZWFyZXN0IG5laWdoYm9ycw0Ka25uNSA8LSBrbm4ybmIoa25lYXJuZWlnaChoZXhfY2VudHJvaWRzLCBrID0gMTApKQ0Ka25uNSA8LSBpbmNsdWRlLnNlbGYoa25uNSkNCg0KIyBDcmVhdGluZyB0aGUgbG9jYWxHIHN0YXRpc3RpYyBmb3IgZWFjaCBvZiBjb3VudGllcywgd2l0aCBhIGstbmVhcmVzdCBuZWlnaGJvciB2YWx1ZSBvZiA1LCBhbmQgcm91bmQgdGhpcyB0byAzIGRlY2ltYWwgcGxhY2VzDQpsb2NhbEd2YWx1ZXMgPC0gbG9jYWxHKHggPSBhcy5udW1lcmljKGhleF9wb2x5Z29uc19FV19kZiRwZW9wbGVfd29fZ2FyKSwgbGlzdHcgPSBuYjJsaXN0dyhrbm41LCBzdHlsZSA9ICJCIiksIHplcm8ucG9saWN5ID0gVFJVRSkNCmxvY2FsR3ZhbHVlcyA8LSByb3VuZChsb2NhbEd2YWx1ZXMsMykNCg0KIyBDcmVhdGUgYSBuZXcgZGF0YSBmcmFtZSB0aGF0IG9ubHkgaW5jbHVkZXMgdGhlIGhleG9nb25zIGFuZCB0aGUgRyBzY29yZXMNCm5ld19kZiA8LSBoZXhfcG9seWdvbnNfRVcgDQpuZXdfZGYkdmFsdWVzIDwtIGxvY2FsR3ZhbHVlcw0KDQpuZXdfZGYgJT4lIA0KICBnZ3Bsb3QoYWVzKHZhbHVlcyArIDEuNSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oKQ0KDQpzdW0obmV3X2RmJHZhbHVlcyA9PSAwKQ0KDQpnZ3Bsb3QoKSArDQogICNnZW9tX3NmKGRhdGEgPSBtYXBfYm91bmQpICsNCiAgI2dlb21fc2YoZGF0YSA9IHN0X2NlbnRyb2lkKG1zb2FfYm91bmQpLCBjb2xvdXIgPSAiZ3JleSIpICsNCiAgZ2VvbV9zZihkYXRhID0gbmV3X2RmLCBtYXBwaW5nID0gYWVzKGZpbGwgPSB2YWx1ZXMgKyAxLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSB2YWx1ZXMgKyAxLjUpKSArDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKHRyYW5zID0gImxvZyIsIG9wdGlvbiA9ICJtYWdtYSIsIGJlZ2luID0gMCkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKHRyYW5zID0gImxvZyIsIG9wdGlvbiA9ICJtYWdtYSIsIGJlZ2luID0gMCkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSkNCmBgYA0KDQpMb29raW5nIGF0IGNoYW5nZSBpbiBwYXJrIHVzYWdlIChpbiB0d28gcGVyaW9kcyBpbiAyMDIwKSB2cyBnYXJkZW4gYWNjZXNzLg0KDQpbVXNhZ2UgZGF0YSBmcm9tIEdvb2dsZSB2aWEgT05TXShodHRwczovL3d3dy5vbnMuZ292LnVrL2Vjb25vbXkvZW52aXJvbm1lbnRhbGFjY291bnRzL2FydGljbGVzL2hvd2hhc2xvY2tkb3duY2hhbmdlZG91cnJlbGF0aW9uc2hpcHdpdGhuYXR1cmUvMjAyMS0wNC0yNikNCg0KYGBge3J9DQoNCiMgcmVhZCBpbiBHb29nbGUvT05TIHBhcmsgdXNhZ2UgZGF0YQ0KcGFya191c2VhZ2UgPC0gcmVhZF94bHN4KCJkYXRhL2NoYW5nZV9pbl9wYXJrc192aXNpdHNfMjAyMF9MQS54bHN4Iiwgc2tpcCA9IDYpICU+JQ0KICANCiAgIyBhcHBseSBjb25zaXN0ZW50IG5hbWluZyBzdHlsZQ0KICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JSANCiAgDQogICMgc2hvcnRlbiBuYW1lcyBmb3IgcmVhZGlibGl0eQ0KICByZW5hbWUocGVyY19jaF9wYXJrc19zcHJpbmdfbG9jayA9IHBlcmNlbnRfY2hhbmdlX2luX3Zpc2l0c190b19hbmRfdGltZV9zcGVudF9pbl9wYXJrc19kdXJpbmdfc3ByaW5nXzIwMjBfbG9ja2Rvd24sDQogICAgICAgICBwZXJjX2NoX3Bhcmtfc3VtbWVyID0gcGVyY2VudF9jaGFuZ2VfaW5fdmlzaXRzX3RvX2FuZF90aW1lX3NwZW50X2luX3BhcmtzX2R1cmluZ19qdWx5X2FuZF9hdWd1c3RfMjAyMCwNCiAgICAgICAgIGxhZF9jb2RlID0gYXJlYV9jb2RlcywNCiAgICAgICAgIGxhZF9uYW1lID0gYXJlYV9uYW1lcykNCg0KcGFya191c2VhZ2UNCg0KIyByZWFkIGluIHVyYmFuIC8gcnVyYWwgY2xhc3NpZmljYXRpb24NCnVyYl9ydXJfY2xhc3MgPC0gcmVhZF9jc3YoImRhdGEvUnVyYWxfVXJiYW5fQ2xhc3NpZmljYXRpb25fKDIwMDEpX2Zvcl9NU09Bc19pbl9FbmdsYW5kX2FuZF9XYWxlcy9SVUNfTVNPQV8yMDAxX0VXX0xVLmNzdiIpICU+JSANCiAgY2xlYW5fbmFtZXMoKSAlPiUgDQogIHNlbGVjdChsYWRfY29kZSA9IGxhZDAxY2QsIGxhZF9uYW1lID0gbGFkMDFubSwgDQogICAgICAgICBjbGFzc19uYW1lID0gbW9ycGhvbG9neV9uYW1lLCANCiAgICAgICAgIGNsYXNzX2NvZGUgPSBtb3JwaG9sb2d5X2NvZGUpDQoNCiMgcHJvY2VzcyB1cmJhbiAvIHJ1cmFsIGNsYXNzaWZpY2F0aW9uIA0KdXJiX3J1cl9MQUQgPC0gdXJiX3J1cl9jbGFzcyAlPiUgDQogIG11dGF0ZShpc191cmJhbiA9IGNsYXNzX2NvZGUgPT0gMSkgJT4lIA0KICBncm91cF9ieShsYWRfbmFtZSkgJT4lIA0KICBzdW1tYXJpc2Uobl90b3QgPSBuKCksDQogICAgICAgICAgICBuX3VyYmFuID0gc3VtKGlzX3VyYmFuKSwNCiAgICAgICAgICAgIHByb3BfdXJiYW4gPSBuX3VyYmFuIC8gbl90b3QpICU+JSANCiAgbXV0YXRlKGlzX3VyYmFuX0xBRCA9IHByb3BfdXJiYW4gPiAwLjc1KQ0KDQojIHJlYWQgaW4gTEEgYm91bmRhcmllcw0KTEFfYm91bmRzIDwtIHN0X3JlYWQoImRhdGEvTEFfYm91bmQvTG9jYWxfQXV0aG9yaXR5X0Rpc3RyaWN0c18oRGVjZW1iZXJfMjAxOSlfQm91bmRhcmllc19VS19CRkMuc2hwIikgJT4lIA0KICByZW5hbWUobGFkX2NvZGUgPSBsYWQxOWNkLA0KICAgICAgICAgbGFkX25hbWUgPSBsYWQxOW5tICkNCg0KTEFfYm91bmRzDQoNCiMgYWdncmVnYXRlIGdhcmRlbnMgZGF0YSB0byBMQUQgc2NhbGUNCmdhcmRlbnNfTEFEIDwtIGdhcmRlbnMgJT4lIA0KICBtdXRhdGUoYWRfd29fZ2FyID0gcm91bmQoYWRfY291bnQgKiAoMSAtIHBlcmNfb2ZfYWRlc193aXRoX2dhcikpKSAlPiUgDQogIGdyb3VwX2J5KGxhZF9jb2RlLCBsYWRfbmFtZSkgJT4lIA0KICBzdW1tYXJpc2UoYWRfY291bnQgPSBzdW0oYWRfY291bnQpLA0KICAgICAgICAgICAgYWRfd29fZ2FyID0gc3VtKGFkX3dvX2dhciksDQogICAgICAgICAgICBwcm9wX2FkX3dvX2dhciA9IGFkX3dvX2dhciAvIGFkX2NvdW50KSANCg0KIyBqb2luIGRhdCBzZXRzDQpnYXJfcGFya191c2UgPC0gcGFya191c2VhZ2UgJT4lIA0KICBsZWZ0X2pvaW4oZ2FyZGVuc19MQUQpICU+JSANCiAgbGVmdF9qb2luKHVyYl9ydXJfTEFEKQ0KDQojIGNoZWNrIGZvciBOQSBjcmVhdGVkIGR1cmluZyBqb2luaW5nDQpnYXJfcGFya191c2UgJT4lIA0KICBza2ltcjo6c2tpbSgpDQoNCmdhcl9wYXJrX3VzZSAlPiUgDQogIGZpbHRlcihpcy5uYShpc191cmJhbl9MQUQpKQ0KDQojIHByb2R1Y2UgcGxvdA0KZ2dwbG90KGdhcl9wYXJrX3VzZSwgYWVzKHByb3BfYWRfd29fZ2FyLCBwZXJjX2NoX3BhcmtzX3NwcmluZ19sb2NrLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGlzX3VyYmFuX0xBRCkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKw0KICAjc2NhbGVfeF9sb2cxMCgpICsNCiAgeGxpbShjKDAsMC41KSkgKw0KICBmYWNldF93cmFwKH5pc191cmJhbl9MQUQpDQoNCmdncGxvdChnYXJfcGFya191c2UsIGFlcyhwcm9wX2FkX3dvX2dhciwgcGVyY19jaF9wYXJrX3N1bW1lcikpICsNCiAgZ2VvbV9wb2ludCgpDQoNCm1vZF8xIDwtIHJzdGFuYXJtOjpzdGFuX2dsbShwZXJjX2NoX3BhcmtzX3NwcmluZ19sb2NrIH4gcHJvcF9hZF93b19nYXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBmaWx0ZXIoZ2FyX3BhcmtfdXNlLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb3BfYWRfd29fZ2FyIDwgMC4yICYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNfdXJiYW5fTEFEID09IFRSVUUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWZyZXNoID0gMCkNCg0KbWVkaWFuKHJzdGFuYXJtOjpiYXllc19SMihtb2RfMSkpDQpgYGANCg0KYGBge3J9DQpmb2VfZ3JlZW5fc3BhY2UgPC0gcmVhZF94bHN4KCJkYXRhLyhGT0UpIEdyZWVuIFNwYWNlIENvbnNvbGlkYXRlZCBEYXRhIC0gRW5nbGFuZCAtIFZlcnNpb24gMi4xLnhsc3giLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9ICJMb2NhbCBBdXRob3JpdGllcyBWMi4xIikgJT4lIA0KICBjbGVhbl9uYW1lcygpICU+JSANCiAgc2VsZWN0KGxhZF9jb2RlID0gbGFfY29kZSwgDQogICAgICAgICBsYWRfbmFtZSA9IGxhX25hbWUsDQogICAgICAgICBwb3AgPSB0b3RhbF9wb3BfZnJvbV9ldGhuaWNpdHlfZGF0YSwNCiAgICAgICAgIGJhbWVfcG9wLA0KICAgICAgICAgaW5jb21lX2luZGV4LA0KICAgICAgICAgcGNudF9wb3Bfd2l0aF9nb19zcGFjZV9hY2Nlc3MsDQogICAgICAgICBncmVlbl9zcGFjZV9hcmVhX3Blcl9jYXBpdGEpDQoNCiMgam9pbiBmb2UgZGF0YSB0byBleGlzdGluZyBkYXRhDQpnYXJfcGFya191c2VfZm9lIDwtIGdhcl9wYXJrX3VzZSAlPiUgDQogIGxlZnRfam9pbihmb2VfZ3JlZW5fc3BhY2UpDQoNCiMgY2hlY2sgTkFzIGNyZWF0ZWQgYnkgam9pbmluZw0Kc2tpbXI6OnNraW0oZ2FyX3BhcmtfdXNlX2ZvZSkNCmdhcl9wYXJrX3VzZV9mb2UgJT4lIA0KICBmaWx0ZXIoaXMubmEocG9wKSkgICMgYWxtb3N0IGFsbCBTY290bGFuZCBhbmQgV2FsZXMgDQogICAgICAgICAgICAgICAgICAgICAgIyAoYXMgZXhwZWN0ZWQgYXMgRk9FIGlzIEVuZ2xhbmQgb25seSkNCg0KDQpnYXJfcGFya191c2VfZm9lX2VuZyA8LSBnYXJfcGFya191c2VfZm9lICU+JSANCiAgZmlsdGVyKCFpcy5uYShwb3ApKSAlPiUgDQogIG11dGF0ZShwZXJjX2NoX3Bhcmtfc3VtbWVyID0gbmFfaWYocGVyY19jaF9wYXJrX3N1bW1lciwgIk5vIGRhdGEiKSwNCiAgICAgICAgIHBlcmNfY2hfcGFya19zdW1tZXIgPSBhcy5udW1lcmljKHBlcmNfY2hfcGFya19zdW1tZXIpLA0KICAgICAgICAgcHJvcF9iYW1lX3BvcCA9IGJhbWVfcG9wIC8gcG9wKQ0KDQpnYXJfcGFya191c2VfZm9lX2VuZw0KDQpnYXJfcGFya191c2VfZm9lX2VuZ19tb2RfaW4gPC0gZ2FyX3BhcmtfdXNlX2ZvZV9lbmcgJT4lIA0KICBzZWxlY3QoLWxhZF9jb2RlLCAtbGFkX25hbWUsIC1wb3AsIC1iYW1lX3BvcCwNCiAgICAgICAgIC1uX3RvdCwgLW5fdXJiYW4sIC1pc191cmJhbl9MQUQsIC1hZF9jb3VudCwtYWRfd29fZ2FyLA0KICAgICAgICAgLXBlcmNfY2hfcGFya19zdW1tZXIsIC1wY250X3BvcF93aXRoX2dvX3NwYWNlX2FjY2VzcywgLWdyZWVuX3NwYWNlX2FyZWFfcGVyX2NhcGl0YSkNCiAgDQoNCm1vZF8yIDwtIHJzdGFuYXJtOjpzdGFuX2dsbShwZXJjX2NoX3BhcmtzX3NwcmluZ19sb2NrIH4gLiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGdhcl9wYXJrX3VzZV9mb2VfZW5nX21vZF9pbiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmcmVzaCA9IDApDQoNCm1lZGlhbihyc3RhbmFybTo6YmF5ZXNfUjIobW9kXzIpKQ0KDQptb2RfMyA8LSByc3RhbmFybTo6c3Rhbl9nbG0ocGVyY19jaF9wYXJrc19zcHJpbmdfbG9jayB+IHByb3BfYWRfd29fZ2FyICsgcHJvcF91cmJhbiArIGluY29tZV9pbmRleCArIHByb3BfYmFtZV9wb3AsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBnYXJfcGFya191c2VfZm9lX2VuZ19tb2RfaW4sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZnJlc2ggPSAwKQ0KDQptZWRpYW4ocnN0YW5hcm06OmJheWVzX1IyKG1vZF8zKSkNCg0KZ2dwbG90KGdhcl9wYXJrX3VzZV9mb2VfZW5nX21vZF9pbiwgYWVzKHByb3BfYmFtZV9wb3AsIHBlcmNfY2hfcGFya3Nfc3ByaW5nX2xvY2spKSArDQogIGdlb21fcG9pbnQoKQ0KDQpwIDwtIGdncGxvdChmaWx0ZXIoZ2FyX3BhcmtfdXNlX2ZvZV9lbmcsIHByb3BfdXJiYW4gPiAwLjgpLCANCiAgICAgICBhZXMocHJvcF9hZF93b19nYXIsIHBlcmNfY2hfcGFya3Nfc3ByaW5nX2xvY2ssIA0KICAgICAgICAgICBjb2xvdXIgPSBwcm9wX2JhbWVfcG9wLCANCiAgICAgICAgICAgc2l6ZSA9IGdyZWVuX3NwYWNlX2FyZWFfcGVyX2NhcGl0YSwNCiAgICAgICAgICAgbGFiZWwgPSBsYWRfbmFtZSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKCkgKw0KICB4bGltKGMoMCwuNSkpDQogICNzY2FsZV94X2xvZzEwKCkNCg0KcGxvdGx5OjpnZ3Bsb3RseShwKQ0KDQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGZpbHRlcihnYXJfcGFya191c2VfZm9lX2VuZywgcHJvcF91cmJhbiA+IDAuOCksDQogICAgICAgICAgICAgYWVzKHByb3BfYmFtZV9wb3AsIHByb3BfYWRfd29fZ2FyKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICB5bGltKGMoMCwwLjUpKQ0KDQpwMg0KDQpwMyA8LSBnZ3Bsb3QoZmlsdGVyKGdhcl9wYXJrX3VzZV9mb2VfZW5nLCBwcm9wX3VyYmFuID4gMC44KSwgDQogICAgICAgYWVzKHByb3BfYmFtZV9wb3AsIHBlcmNfY2hfcGFya3Nfc3ByaW5nX2xvY2ssIA0KICAgICAgICAgICBjb2xvdXIgPSBwcm9wX2FkX3dvX2dhciwgDQogICAgICAgICAgIHNpemUgPSBncmVlbl9zcGFjZV9hcmVhX3Blcl9jYXBpdGEsDQogICAgICAgICAgIGxhYmVsID0gbGFkX25hbWUpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhkaXJlY3Rpb24gPSAtMSwgdHJhbnMgPSAibG9nIiwgZW5kID0gMC45KSArDQogIHhsaW0oYygwLC41KSkNCg0KcDMNCnBsb3RseTo6Z2dwbG90bHkocDMpDQoNCnA0IDwtIGdncGxvdChmaWx0ZXIoZ2FyX3BhcmtfdXNlX2ZvZV9lbmcsIHByb3BfdXJiYW4gPiAwLjgpLCANCiAgICAgICBhZXMocGVyY19jaF9wYXJrc19zcHJpbmdfbG9jaywgcGVyY19jaF9wYXJrX3N1bW1lciwNCiAgICAgICAgICAgY29sb3VyID0gcHJvcF9hZF93b19nYXIsDQogICAgICAgICAgIHNpemUgPSBncmVlbl9zcGFjZV9hcmVhX3Blcl9jYXBpdGEsDQogICAgICAgICAgIGxhYmVsID0gbGFkX25hbWUpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKGRpcmVjdGlvbiA9IC0xLCB0cmFucyA9ICJsb2ciLCBlbmQgPSAwLjkpDQoNCnA0DQoNCnBsb3RseTo6Z2dwbG90bHkocDQpDQpgYGANCg0KTWFqb3IgY2l0aWVzDQoNCmBgYHtyfQ0KbGFfcmVnaW9uX2xvb2t1cCA8LSBnYXJkZW5zICU+JQ0KICBzZWxlY3QocmVnaW9uX2NvZGU6bGFkX25hbWUpICU+JSANCiAgZGlzdGluY3QoKQ0KDQpsb25kb24gPC0gZ2FyX3BhcmtfdXNlX2ZvZV9lbmcgJT4lIA0KICBsZWZ0X2pvaW4obGFfcmVnaW9uX2xvb2t1cCkgJT4lIA0KICBmaWx0ZXIocmVnaW9uX25hbWUgPT0gIkxvbmRvbiIpDQoNCm90aGVyX2JpZ19jaXRpZXMgPC0gZ2FyX3BhcmtfdXNlX2ZvZV9lbmcgJT4lIA0KICBsZWZ0X2pvaW4obGFfcmVnaW9uX2xvb2t1cCkgJT4lIA0KICBmaWx0ZXIocmVnaW9uX25hbWUgIT0gIkxvbmRvbiIpICU+JSANCiAgZmlsdGVyKHByb3BfdXJiYW4gPj0gMC44KSAlPiUgDQogIHNsaWNlX21heChvcmRlcl9ieSA9IHBvcCwgbiA9IDI5KQ0KDQp0aGlydHlfYmlnZ2VzdF9jaXRpZXMgPC0gbG9uZG9uICU+JSANCiAgYmluZF9yb3dzKG90aGVyX2JpZ19jaXRpZXMpICU+JSANCiAgbXV0YXRlKGlzX2xvbmRvbiA9IHJlZ2lvbl9uYW1lID09ICJMb25kb24iLA0KICAgICAgICAgZ3NfcGNfYmluID0gY3V0KGdyZWVuX3NwYWNlX2FyZWFfcGVyX2NhcGl0YSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKDAsIDEwLCAyNSwgNTAsIEluZikpLA0KICAgICAgICAgcHJvcF9hZF93aXRoX2dhciA9IDEgLSBwcm9wX2FkX3dvX2dhcikNCg0KY29sb3VycyA8LSBjKCJncmV5MzAiLCAiZ3JleTcwIiwgInBhbGVncmVlbiIsICJwYWxlZ3JlZW40IikNCg0KcCA8LSBnZ3Bsb3QodGhpcnR5X2JpZ2dlc3RfY2l0aWVzLCANCiAgICAgICBhZXMocHJvcF9hZF93aXRoX2dhciwgcGVyY19jaF9wYXJrc19zcHJpbmdfbG9jaywgDQogICAgICAgICAgIGNvbG91ciA9IGdzX3BjX2JpbiwgDQogICAgICAgICAgIHNpemUgPSBnc19wY19iaW4sDQogICAgICAgICAgIGxhYmVsID0gbGFkX25hbWUpKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjUpICsNCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJzKSArDQogICNzY2FsZV9jb2xvdXJfdmlyaWRpc19jKCkgKw0KICAjc2NhbGVfY29sb3VyX2dyYWRpZW50KGxvdyA9ICJncmV5MzAiLCBoaWdoID0gImdyZWVuIikgKw0KICB4bGltKGMoMC41LDEpKSArDQogIGZhY2V0X3dyYXAofmlzX2xvbmRvbikNCiAgI3NjYWxlX3hfbG9nMTAoKQ0KDQpwbG90bHk6OmdncGxvdGx5KHApDQoNCmdncGxvdCh0aGlydHlfYmlnZ2VzdF9jaXRpZXMpICsNCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyhncmVlbl9zcGFjZV9hcmVhX3Blcl9jYXBpdGEpKQ0KDQpwNCA8LSBnZ3Bsb3QodGhpcnR5X2JpZ2dlc3RfY2l0aWVzLCANCiAgICAgICBhZXMocGVyY19jaF9wYXJrc19zcHJpbmdfbG9jaywgcGVyY19jaF9wYXJrX3N1bW1lciwNCiAgICAgICAgICAgY29sb3VyID0gZ3JlZW5fc3BhY2VfYXJlYV9wZXJfY2FwaXRhLA0KICAgICAgICAgICBzaXplID0gZ3JlZW5fc3BhY2VfYXJlYV9wZXJfY2FwaXRhLA0KICAgICAgICAgICBsYWJlbCA9IGxhZF9uYW1lKSkgKw0KICBnZW9tX3BvaW50KGFscGhhID0gMC41KSsNCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhlbmQgPSAwLjkpICsNCiAgZmFjZXRfd3JhcCh+aXNfbG9uZG9uKQ0KDQpwNA0KDQpwbG90bHk6OmdncGxvdGx5KHA0KQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShubmdlbykNCg0KIyBpZGVudGlmeSBuZWFyZXN0IG5laWdoYm91cnMgYW5kIGNvbnZlcnQgYWxvZ2l0aG1uIG91dHB1dCB0byBhIGRhdGFmcmFtZQ0KbmVpZ2hfaGV4IDwtIHN0X25uKGhleF9wb2x5Z29uc19FVywgaGV4X3BvbHlnb25zX0VXLCBrID0gNikNCm5laWdoX2hleCA8LSBkYXRhLmZyYW1lKG1hdHJpeCh1bmxpc3QobmVpZ2hfaGV4KSwgbmNvbCA9IG1heChsZW5ndGhzKG5laWdoX2hleCkpLCBieXJvdyA9IFRSVUUpKQ0KDQpsb29rX3VwX3Blb3Bfd29fZ2FyIDwtIGZ1bmN0aW9uKGRmLCByb3dfbnVtKXsNCiAgZGZbcm93X251bSwgJ3Blb3BsZV93b19nYXInXSAlPiUgDQogICAgc3RfZHJvcF9nZW9tZXRyeSgpICU+JSANCiAgICBwbHVjaygncGVvcGxlX3dvX2dhcicpDQp9DQoNCg0KIyByZXNldCByb3cgbnVtYmVycyB0byBhdm9pZCBjb25mdXNpb24gd2hlbiBhZGRpbmcgbmVhcmVzdCBuZWlnaGJvcnMNCnJvdy5uYW1lcyhoZXhfcG9seWdvbl9FVykgPC0gTlVMTA0KDQojIGFkZCBuZWFyZXN0IG5laWdoYm9ycyB0byBwb2x5Z29uDQpoZXhfcG9seWdvbl9FV19ubiA8LSBoZXhfcG9seWdvbl9FVyAlPiUgDQogIGJpbmRfY29scyhuZWlnaF9oZXgpDQoNCg0Ka25uX2ludGVycG9sYXRpb24gPC0gaGV4X3BvbHlnb25fRVdfbm4gJT4lIA0KICBtdXRhdGUoYWNyb3NzKFgxOlg2LCB+IGxvb2tfdXBfcGVvcF93b19nYXIoaGV4X3BvbHlnb25fRVdfbm4sIC4pKSkgJT4lIA0KICBzdF9kcm9wX2dlb21ldHJ5KCkgJT4lIA0KICBtdXRhdGUoa25uX2F2ZSA9IHJvdW5kKHJvd01lYW5zKHNlbGVjdCguLCBzdGFydHNfd2l0aCgiWCIpKSkpKSAlPiUgDQogIHB1bGwoa25uX2F2ZSkNCiAgDQpoZXhfcG9seWdvbl9FV19ubiAlPiUgDQogIGJpbmRfY29scyhrbm5faW50ZXJwb2xhdGlvbikNCg0KaGV4X3BvbHlnb25faW50ZXJwb2xhdGlvbg0KYGBgDQo=